package auth.service.impl;

import auth.service.GoodsServiceFeignClient;
import auth.service.IAdminService;
import auth.service.IUserService;
import auth.service.OrderServiceFeignClient;
import auth.service.ShopServiceFeignClient;

import common.dto.goodsdto.GoodsDTO;
import common.dto.shopdto.ShopDTO;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;

import auth.mapper.AdminMapper;
import common.model.result.Result;
import common.model.result.ResultCodeEnum;
import common.model.admin.AdminRole;
import common.model.admin.AdminUser;
import common.model.order.Orders;
import auth.mapper.AdminRoleMapper;
import auth.mapper.AdminRolePermissionMapper;
import common.dto.admindto.AdminPermissionDTO;
import common.dto.admindto.AdminToken;
import common.dto.admindto.Permission;
import common.model.admin.AdminPermission;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletResponse;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import common.model.admin.AdminRolePermission;
import auth.mapper.AdminPermissionMapper;
import common.utils.PasswordUtil;
import common.dto.admindto.AdminDashboard;
import common.dto.admindto.AdminLogin;
import common.dto.userdto.UserDTO;

import java.math.BigDecimal;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Date;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import auth.utils.JwtUtil;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Service
public class AdminServiceImpl implements IAdminService {
    //管理员mapper
    @Autowired
    private AdminMapper adminMapper;

    //角色mapper
    @Autowired
    private AdminRoleMapper adminRoleMapper;

    //角色权限mapper
    @Autowired
    private AdminRolePermissionMapper adminRolePermissionMapper;

    //权限mapper
    @Autowired
    private AdminPermissionMapper adminPermissionMapper;

    //用户服务
    @Autowired
    private IUserService userService;

    //订单Feign
    @Autowired
    private OrderServiceFeignClient orderServiceFeignClient;

    //商品Feign
    @Autowired
    private GoodsServiceFeignClient goodsServiceFeignClient;

    //商铺Feign
    @Autowired
    private ShopServiceFeignClient serviceFeignClient;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    
    @Autowired
    private JwtUtil jwtUtil;

    //后台登录
    @Override
    public Result login(AdminLogin adminLogin, HttpServletResponse response) {
        // 1. 参数校验
        if (adminLogin == null || adminLogin.getUsername() == null || adminLogin.getPassword() == null) {
            return Result.failure(ResultCodeEnum.FAIL, "用户名或密码不能为空");
        }
        
        // 2. 根据用户名查询管理员
        AdminUser admin = adminMapper.selectOne(
            new LambdaQueryWrapper<AdminUser>()
                .eq(AdminUser::getUsername, adminLogin.getUsername())
                .eq(AdminUser::getIsDeleted, 0) 
        );
        
        // 3. 校验管理员是否存在
        if (admin == null) {
            return Result.failure(ResultCodeEnum.FAIL, "用户名或密码错误");
        }
        System.out.println("管理员: " + admin.getStatus());
        // 4. 校验管理员状态
        if (admin.getStatus() != 1) {
            String statusMsg = admin.getStatus() == 0 ? "账号已禁用" : "账号已锁定";
            return Result.failure(ResultCodeEnum.FAIL, statusMsg);
        }
        
        System.out.println("输入密码: " + adminLogin.getPassword());
        System.out.println("数据库密码哈希: " + admin.getPasswordHash());
        
        
        System.out.println("密码验证成功");
        // 6. 更新管理员登录信息
        admin.setLoginFailCount(0); // 重置登录失败次数
        admin.setLastLoginTime(LocalDateTime.now());
        admin.setOnline(true);
        // TODO: 获取真实IP
        admin.setLastLoginIp(getClientIp());
        adminMapper.updateById(admin);
        
        // 7. 生成AdminToken对象
        AdminToken adminToken = new AdminToken();
        
        // 8. 生成accessToken (有效期2小时)
        Map<String, Object> accessClaims = new HashMap<>();
        accessClaims.put("id", admin.getId());
        accessClaims.put("username", adminLogin.getUsername());
        accessClaims.put("roleId", admin.getRoleId());
        accessClaims.put("type", "access");
        
        String accessToken = generateToken(accessClaims, 2 * 60 * 60 * 1000); // 2小时
        adminToken.setAccessToken(accessToken);
        adminToken.setExpiresIn(2 * 60 * 60); // 2小时(秒)
        adminToken.setRoleId(admin.getRoleId());
        
        // 9. 生成refreshToken (有效期7天)
        Map<String, Object> refreshClaims = new HashMap<>();
        refreshClaims.put("id", admin.getId());
        refreshClaims.put("username", admin.getUsername());
        refreshClaims.put("roleId", admin.getRoleId());
        refreshClaims.put("type", "refresh");
        
        String refreshToken = generateToken(refreshClaims, 7 * 24 * 60 * 60 * 1000); // 7天
        
        // 10. 将refreshToken存入HttpOnly Cookie
        Cookie cookie = new Cookie("admin_refresh_token", refreshToken);
        cookie.setHttpOnly(true);
        cookie.setPath("/");
        cookie.setMaxAge(7 * 24 * 60 * 60); // 7天(秒)
        // 在生产环境中应该设置secure=true
        // cookie.setSecure(true);
        response.addCookie(cookie);
        
        return Result.success(adminToken);
    }

    //后台登出
    @Override
    public Result logout(HttpServletRequest request, HttpServletResponse response) {
        Long userId = Long.parseLong(request.getHeader("uid"));

        // 1. 获取accessToken
        String accessToken = request.getHeader("Authorization");
        if (accessToken != null && accessToken.startsWith("Bearer ")) {
            accessToken = accessToken.substring(7);
        }
        
        // 2. 获取refreshToken
        Cookie[] cookies = request.getCookies();
        String refreshToken = null;
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("admin_refresh_token".equals(cookie.getName())) {
                    refreshToken = cookie.getValue();
                    break;
                }
            }
        }



        // 3. 将两个token加入黑名单
        if (accessToken != null) {
            try {
                // 解析token获取过期时间
                Claims claims = jwtUtil.parseToken(accessToken);
                Date expiration = claims.getExpiration();
                // 计算剩余过期时间（毫秒）
                long ttl = expiration.getTime() - System.currentTimeMillis();
                if (ttl > 0) {
                    // 将token加入黑名单，过期时间与token剩余有效期一致
                    stringRedisTemplate.opsForValue().set(
                        "token:blacklist:" + accessToken,
                        "1",
                        ttl,
                        TimeUnit.MILLISECONDS
                    );
                }
            } catch (Exception e) {
                // token解析失败，可能已经过期
            }
        }
        
        if (refreshToken != null) {
            try {
                // 解析token获取过期时间
                Claims claims = jwtUtil.parseToken(refreshToken);
                Date expiration = claims.getExpiration();
                // 计算剩余过期时间（毫秒）
                long ttl = expiration.getTime() - System.currentTimeMillis();
                if (ttl > 0) {
                    // 将token加入黑名单，过期时间与token剩余有效期一致
                    stringRedisTemplate.opsForValue().set(
                        "token:blacklist:" + refreshToken,
                        "1",
                        ttl,
                        TimeUnit.MILLISECONDS
                    );
                }
            } catch (Exception e) {
                // token解析失败，可能已经过期
            }
        }
        
        // 4. 清除客户端Cookie
        Cookie cookie = new Cookie("admin_refresh_token", null);
        cookie.setHttpOnly(true);
        cookie.setPath("/");
        cookie.setMaxAge(0); // 立即删除
        response.addCookie(cookie);

        // 5.下线
        AdminUser admin = adminMapper.selectById(Long.parseLong(request.getHeader("uid")));
        admin.setLastLoginTime(LocalDateTime.now());
        admin.setLastLoginIp(getClientIp());
        admin.setOnline(false);
        admin.setLastOnlineTime(LocalDateTime.now());
        adminMapper.updateById(admin);

        return Result.success("登出成功");
    }
    
    //刷新token
    @Override
    public Result refreshToken(HttpServletRequest request, HttpServletResponse response) {
        // 1. 从Cookie中获取RefreshToken
        Cookie[] cookies = request.getCookies();
        String refreshToken = null;
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("admin_refresh_token".equals(cookie.getName())) {
                    refreshToken = cookie.getValue();
                    break;
                }
            }
        }
        
        // 2. 验证RefreshToken
        if (refreshToken == null) {
            return Result.failure(ResultCodeEnum.FAIL, "刷新令牌不存在");
        }
        
        // 3. 检查refreshToken是否在黑名单中
        if (Boolean.TRUE.equals(stringRedisTemplate.hasKey("token:blacklist:" + refreshToken))) {
            return Result.failure(ResultCodeEnum.FAIL, "刷新令牌已失效");
        }
        
        // 4. 验证refreshToken的有效性
        try {
            Claims claims = jwtUtil.parseToken(refreshToken);
            
            // 5. 检查token类型
            if (!"refresh".equals(claims.get("type"))) {
                return Result.failure(ResultCodeEnum.FAIL, "令牌类型错误");
            }
            
            // 6. 获取管理员ID
            Long adminId = Long.valueOf(claims.get("id").toString());
            
            // 7. 查询管理员信息
            AdminUser admin = adminMapper.selectById(adminId);
            if (admin == null || admin.getIsDeleted() == 1 || admin.getStatus() != 1) {
                return Result.failure(ResultCodeEnum.FAIL, "管理员不存在或已被禁用");
            }
            
            // 8. 生成新的AdminToken对象
            AdminToken adminToken = new AdminToken();
            
            // 9. 生成新的accessToken (有效期2小时)
            Map<String, Object> accessClaims = new HashMap<>();
            accessClaims.put("id", admin.getId());
            accessClaims.put("username", admin.getUsername());
            accessClaims.put("roleId", admin.getRoleId());
            accessClaims.put("type", "access");
            
            String accessToken = generateToken(accessClaims, 2 * 60 * 60 * 1000); // 2小时
            adminToken.setAccessToken(accessToken);
            adminToken.setExpiresIn(2 * 60 * 60); // 2小时(秒)
            adminToken.setRoleId(admin.getRoleId());
            
            return Result.success(adminToken);
            
        } catch (Exception e) {
            return Result.failure(ResultCodeEnum.FAIL, "刷新令牌无效");
        }
    }
    
    /**
     * 生成JWT令牌
     * @param claims 载荷
     * @param expiration 过期时间(毫秒)
     * @return JWT令牌
     */
    private String generateToken(Map<String, Object> claims, long expiration) {
        return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(Keys.hmacShaKeyFor("8Zz5tw0Ionm3XPZZfN0NOml3z9FMfmpgXwovR9fp6ryDIoGRM8EPHAB6iHsc0fb".getBytes()))
                .compact();
    }
    
    /**
     * 获取客户端IP地址
     * @return IP地址
     */
    private String getClientIp() {
        return "127.0.0.1"; // 示例IP，实际应从请求中获取
    }

    //仪表盘数据
    @Override
    public Result dashboard() {
        AdminDashboard dashboardData = new AdminDashboard();

        //获取所有订单
        Result allOrders = orderServiceFeignClient.getAllOrders();
        //获取所有用户
        Result userList = userService.getUserList();
        //获取所有商品
        Result allGoods = goodsServiceFeignClient.getAllGoods();
        //获取所有商铺
        Result allShop = serviceFeignClient.getAllShop();

        // 1. 填充顶部汇总数据
        if (allOrders != null && allOrders.getData() != null && allOrders.getData() instanceof List) {
            List<?> rawOrders = (List<?>) allOrders.getData();
            List<Orders> orders = rawOrders.stream()
                                        .map(orderMap -> objectMapper.convertValue(orderMap, Orders.class))
                                        .collect(java.util.stream.Collectors.toList());

            dashboardData.setOrderNumber(orders.size());
            BigDecimal totalSales = orders.stream()
                    .map(Orders::getTotalAmount) // 假设 OrderDTO 有 getAmount() 方法返回 BigDecimal
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            dashboardData.setTotalSales(totalSales);
        } else {
             dashboardData.setOrderNumber(0);
             dashboardData.setTotalSales(BigDecimal.ZERO);
             // 记录日志或返回错误，表示获取订单失败
        }
        // 填充用户数量
        if (userList != null && userList.getSuccess() && userList.getData() != null && userList.getData() instanceof List) {
            dashboardData.setUserNumber(((List<UserDTO>) userList.getData()).size());
        } else dashboardData.setUserNumber(0);

        // 填充商品数量
        if (allGoods != null && allGoods.getSuccess() && allGoods.getData() != null && allGoods.getData() instanceof List) {
             dashboardData.setGoodsNumber(((List<GoodsDTO>) allGoods.getData()).size());
        } else dashboardData.setGoodsNumber(0);

        // 填充商铺数量
        if (allShop != null && allShop.getSuccess() && allShop.getData() != null && allShop.getData() instanceof List) {
             dashboardData.setShopNumber(((List<ShopDTO>) allShop.getData()).size());
        } else dashboardData.setShopNumber(0);
        return Result.success(dashboardData);
    }
    
    //获取所有管理员
    @Override
    public Result findAll() {
        return Result.success(adminMapper.selectList(null));
    }

    //添加管理员
    @Override
    public Result add(AdminUser admin) {
        // 参数校验
        if (admin == null || admin.getUsername() == null || admin.getPasswordHash() == null) {
            return Result.failure(ResultCodeEnum.FAIL, "参数错误");
        }
        
        // 检查用户名是否已存在
        AdminUser existingAdmin = adminMapper.selectOne(
            new LambdaQueryWrapper<AdminUser>()
                .eq(AdminUser::getUsername, admin.getUsername())
                .eq(AdminUser::getIsDeleted, 0)
        );
        
        if (existingAdmin != null) {
            return Result.failure(ResultCodeEnum.FAIL, "用户名已存在");
        }
        
        // 密码哈希加密
        String rawPassword = admin.getPasswordHash();
        String encodedPassword = PasswordUtil.encode(rawPassword);
        admin.setPasswordHash(encodedPassword);
        
        // 设置默认值
        if (admin.getStatus() == null) {
            admin.setStatus(1); // 默认启用
        }
        if (admin.getLoginFailCount() == null) {
            admin.setLoginFailCount(0);
        }
        if (admin.getIsDeleted() == null) {
            admin.setIsDeleted(0);
        }
        
        // 设置创建时间
        admin.setCreatedAt(LocalDateTime.now());
        admin.setUpdatedAt(LocalDateTime.now());
        
        return Result.success(adminMapper.insert(admin));
    }

    //编辑管理员
    @Override
    public Result edit(AdminUser admin) {
        return Result.success(adminMapper.updateById(admin));
    }

    //删除管理员
    @Override
    public Result delete(AdminUser admin) {
        return Result.success(adminMapper.deleteById(admin));
    }

    //角色表
    @Override
    public Result role() {
        return Result.success(adminRoleMapper.selectList(null));
    }
    
    //添加角色
    @Override
    public Result roleAdd(AdminRole adminRole) {
        return Result.success(adminRoleMapper.insert(adminRole));
    }

    //获取权限列表
    @Override
    public Result permission() {
        return Result.success(adminPermissionMapper.selectList(null));
    }

    //获取角色权限列表
    @Override
    public Result RolePermission() {
        //获取所有角色
        List<AdminRole> adminRoles = adminRoleMapper.selectList(null);
        //遍历角色
        List<AdminPermissionDTO> adminPermissionDTOs = new ArrayList<>();
        for (AdminRole adminRole : adminRoles) {
            //管理员权限DTO
            AdminPermissionDTO adminPermissionDTO = new AdminPermissionDTO();
            List<Permission> permissions = new ArrayList<>();
            adminPermissionDTO.setRoleName(adminRole.getName());
            //获取角色权限列表
            List<AdminRolePermission> adminRolePermissions = adminRolePermissionMapper.selectList(new LambdaQueryWrapper<AdminRolePermission>().eq(AdminRolePermission::getRoleId, adminRole.getId()));
            //遍历角色权限列表
            for (AdminRolePermission adminRolePermission : adminRolePermissions) {
                //获取权限
                Permission permission = new Permission();
                AdminPermission adminPermission = adminPermissionMapper.selectById(adminRolePermission.getPermissionId());
                permission.setId(adminPermission.getId());
                permission.setCode(adminPermission.getCode());
                permission.setName(adminPermission.getName());
                permission.setDescription(adminPermission.getDescription());
                //将权限添加到权限列表中
                permissions.add(permission);
            }
            //将管理员权限DTO添加到管理员权限DTO列表中
            adminPermissionDTO.setPermissions(permissions);
            adminPermissionDTOs.add(adminPermissionDTO);
        }
        return Result.success(adminPermissionDTOs);
    }

    //重置管理员密码
    @Override
    public Result resetPassword(Long adminId, String newPassword) {
        if (adminId == null || newPassword == null || newPassword.isEmpty()) {
            return Result.failure(ResultCodeEnum.FAIL, "参数错误");
        }
        
        // 查询管理员
        AdminUser admin = adminMapper.selectById(adminId);
        if (admin == null || admin.getIsDeleted() == 1) {
            return Result.failure(ResultCodeEnum.FAIL, "管理员不存在");
        }
        
        // 使用BCrypt加密新密码
        String encodedPassword = PasswordUtil.encode(newPassword);
        System.out.println("原始密码: " + newPassword);
        System.out.println("加密后密码: " + encodedPassword);
        
        // 更新密码
        admin.setPasswordHash(encodedPassword);
        adminMapper.updateById(admin);
        
        return Result.success("密码重置成功");
    }

    //获取目前的在线客服管理员
    @Override
    public Result getOnlineAdminId() {
        //查找在线的管理员
        List<AdminUser> adminUsers = adminMapper.selectList(
                new LambdaQueryWrapper<AdminUser>()
                        .eq(AdminUser::isOnline, true)
                        .orderByDesc(AdminUser::getRoleId)  // 按roleId降序
        );
        if (adminUsers != null && !adminUsers.isEmpty()) {
            return Result.success(adminUsers.get(0).getId());
        }
        return Result.success("暂无在线管理员");
    }
}
